home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLUT / GLUT_WIN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  27.7 KB  |  998 lines

  1.  
  2. /* Copyright (c) Mark J. Kilgard, 1994, 1997.  */
  3.  
  4. /* This program is freely distributable without licensing fees
  5.    and is provided without guarantee or warrantee expressed or
  6.    implied. This program is -not- in the public domain. */
  7.  
  8. #include <stdlib.h>
  9. #include <stdio.h>
  10. #include <string.h>
  11. #include <assert.h>
  12. #if !defined(_WIN32)
  13. #include <X11/Xlib.h>
  14. #include <X11/Xatom.h>
  15. #endif
  16.  
  17. #include "glutint.h"
  18.  
  19. GLUTwindow *__glutCurrentWindow = NULL;
  20. GLUTwindow **__glutWindowList = NULL;
  21. int __glutWindowListSize = 0;
  22. #if !defined(_WIN32)
  23. GLUTstale *__glutStaleWindowList = NULL;
  24. #endif
  25. GLUTwindow *__glutMenuWindow = NULL;
  26.  
  27. void (*__glutFreeOverlayFunc) (GLUToverlay *);
  28. XVisualInfo *(*__glutDetermineVisualFromString) (char *string, Bool * treatAsSingle,
  29.   Criterion * requiredCriteria, int nRequired, int requiredMask, void** fbc) = NULL;
  30.  
  31. static Criterion requiredWindowCriteria[] =
  32. {
  33.   {LEVEL, EQ, 0},
  34.   {TRANSPARENT, EQ, 0}
  35. };
  36. static int numRequiredWindowCriteria = sizeof(requiredWindowCriteria) / sizeof(Criterion);
  37. static int requiredWindowCriteriaMask = (1 << LEVEL) | (1 << TRANSPARENT);
  38.  
  39. static void
  40. cleanWindowWorkList(GLUTwindow * window)
  41. {
  42.   GLUTwindow **pEntry = &__glutWindowWorkList;
  43.   GLUTwindow *entry = __glutWindowWorkList;
  44.  
  45.   /* Tranverse singly-linked window work list look for the
  46.      window. */
  47.   while (entry) {
  48.     if (entry == window) {
  49.       /* Found it; delete it. */
  50.       *pEntry = entry->prevWorkWin;
  51.       return;
  52.     } else {
  53.       pEntry = &entry->prevWorkWin;
  54.       entry = *pEntry;
  55.     }
  56.   }
  57. }
  58.  
  59. #if !defined(_WIN32)
  60.  
  61. static void
  62. cleanStaleWindowList(GLUTwindow * window)
  63. {
  64.   GLUTstale **pEntry = &__glutStaleWindowList;
  65.   GLUTstale *entry = __glutStaleWindowList;
  66.  
  67.   /* Tranverse singly-linked stale window list look for the
  68.      window ID. */
  69.   while (entry) {
  70.     if (entry->window == window) {
  71.       /* Found it; delete it. */
  72.       *pEntry = entry->next;
  73.       free(entry);
  74.       return;
  75.     } else {
  76.       pEntry = &entry->next;
  77.       entry = *pEntry;
  78.     }
  79.   }
  80. }
  81.  
  82. #endif
  83.  
  84. static GLUTwindow *__glutWindowCache = NULL;
  85.  
  86. GLUTwindow *
  87. __glutGetWindow(Window win)
  88. {
  89.   int i;
  90.  
  91.   /* Does win belong to the last window ID looked up? */
  92.   if (__glutWindowCache && (win == __glutWindowCache->win ||
  93.       (__glutWindowCache->overlay && win ==
  94.         __glutWindowCache->overlay->win))) {
  95.     return
  96.       __glutWindowCache;
  97.   }
  98.   /* Otherwise scan the window list looking for the window ID. */
  99.   for (i = 0; i < __glutWindowListSize; i++) {
  100.     if (__glutWindowList[i]) {
  101.       if (win == __glutWindowList[i]->win) {
  102.         __glutWindowCache = __glutWindowList[i];
  103.         return __glutWindowCache;
  104.       }
  105.       if (__glutWindowList[i]->overlay) {
  106.         if (win == __glutWindowList[i]->overlay->win) {
  107.           __glutWindowCache = __glutWindowList[i];
  108.           return __glutWindowCache;
  109.         }
  110.       }
  111.     }
  112.   }
  113. #if !defined(_WIN32)
  114.   {
  115.     GLUTstale *entry;
  116.  
  117.     /* Scan through destroyed overlay window IDs for which no
  118.        DestroyNotify has yet been received. */
  119.     for (entry = __glutStaleWindowList; entry; entry = entry->next) {
  120.       if (entry->win == win)
  121.         return entry->window;
  122.     }
  123.   }
  124. #endif
  125.   return NULL;
  126. }
  127.  
  128. /* CENTRY */
  129. int APIENTRY
  130. glutGetWindow(void)
  131. {
  132.   if (__glutCurrentWindow) {
  133.     return __glutCurrentWindow->num + 1;
  134.   } else {
  135.     return 0;
  136.   }
  137. }
  138. /* ENDCENTRY */
  139.  
  140. void
  141. __glutSetWindow(GLUTwindow * window)
  142. {
  143.   /* It is tempting to try to short-circuit the call to
  144.      glXMakeCurrent if we "know" we are going to make current
  145.      to a window we are already current to.  In fact, this
  146.      assumption breaks when GLUT is expected to integrated with
  147.      other OpenGL windowing APIs that also make current to
  148.      OpenGL contexts.  Since glXMakeCurrent short-circuits the
  149.      "already bound" case, GLUT avoids the temptation to do so
  150.      too. */
  151.   __glutCurrentWindow = window;
  152.  
  153.   MAKE_CURRENT_LAYER(__glutCurrentWindow);
  154.  
  155. #if !defined(_WIN32)
  156.   /* We should be careful to force a finish between each
  157.      iteration through the GLUT main loop if indirect OpenGL 
  158.      contexts are in use; indirect contexts tend to have  much
  159.      longer latency because lots of OpenGL extension requests
  160.      can queue up in the X protocol stream.  We accomplish this
  161.      by posting GLUT_FINISH_WORK to be done. */
  162.   if (!__glutCurrentWindow->isDirect)
  163.     __glutPutOnWorkList(__glutCurrentWindow, GLUT_FINISH_WORK);
  164. #endif
  165.  
  166.   /* If debugging is enabled, we'll want to check this window
  167.      for any OpenGL errors every iteration through the GLUT
  168.      main loop.  To accomplish this, we post the
  169.      GLUT_DEBUG_WORK to be done on this window. */
  170.   if (__glutDebug) {
  171.     __glutPutOnWorkList(__glutCurrentWindow, GLUT_DEBUG_WORK);
  172.   }
  173. }
  174.  
  175. /* CENTRY */
  176. void APIENTRY
  177. glutSetWindow(int win)
  178. {
  179.   GLUTwindow *window;
  180.  
  181.   if (win < 1 || win > __glutWindowListSize) {
  182.     __glutWarning("glutSetWindow attempted on bogus window.");
  183.     return;
  184.   }
  185.   window = __glutWindowList[win - 1];
  186.   if (!window) {
  187.     __glutWarning("glutSetWindow attempted on bogus window.");
  188.     return;
  189.   }
  190.   __glutSetWindow(window);
  191. }
  192. /* ENDCENTRY */
  193.  
  194. static int
  195. getUnusedWindowSlot(void)
  196. {
  197.   int i;
  198.  
  199.   /* Look for allocated, unused slot. */
  200.   for (i = 0; i < __glutWindowListSize; i++) {
  201.     if (!__glutWindowList[i]) {
  202.       return i;
  203.     }
  204.   }
  205.   /* Allocate a new slot. */
  206.   __glutWindowListSize++;
  207.   if (__glutWindowList) {
  208.     __glutWindowList = (GLUTwindow **)
  209.       realloc(__glutWindowList,
  210.       __glutWindowListSize * sizeof(GLUTwindow *));
  211.   } else {
  212.     /* XXX Some realloc's do not correctly perform a malloc
  213.        when asked to perform a realloc on a NULL pointer,
  214.        though the ANSI C library spec requires this. */
  215.     __glutWindowList = (GLUTwindow **)
  216.       malloc(sizeof(GLUTwindow *));
  217.   }
  218.   if (!__glutWindowList)
  219.     __glutFatalError("out of memory.");
  220.   __glutWindowList[__glutWindowListSize - 1] = NULL;
  221.   return __glutWindowListSize - 1;
  222. }
  223.  
  224. static XVisualInfo *
  225. getVisualInfoCI(unsigned int mode)
  226. {
  227.   static int bufSizeList[] =
  228.   {16, 12, 8, 4, 2, 1, 0};
  229.   XVisualInfo *vi;
  230.   int list[32];
  231.   int i, n = 0;
  232.  
  233.   /* Should not be looking at display mode mask if
  234.      __glutDisplayString is non-NULL. */
  235.   assert(!__glutDisplayString);
  236.  
  237.   list[n++] = GLX_BUFFER_SIZE;
  238.   list[n++] = 1;
  239.   if (GLUT_WIND_IS_DOUBLE(mode)) {
  240.     list[n++] = GLX_DOUBLEBUFFER;
  241.   }
  242.   if (GLUT_WIND_IS_STEREO(mode)) {
  243.     list[n++] = GLX_STEREO;
  244.   }
  245.   if (GLUT_WIND_HAS_DEPTH(mode)) {
  246.     list[n++] = GLX_DEPTH_SIZE;
  247.     list[n++] = 1;
  248.   }
  249.   if (GLUT_WIND_HAS_STENCIL(mode)) {
  250.     list[n++] = GLX_STENCIL_SIZE;
  251.     list[n++] = 1;
  252.   }
  253.   list[n] = (int) None; /* terminate list */
  254.  
  255.   /* glXChooseVisual specify GLX_BUFFER_SIZE prefers the
  256.      "smallest index buffer of at least the specified size".
  257.      This would be reasonable if GLUT allowed the user to
  258.      specify the required buffe size, but GLUT's display mode
  259.      is too simplistic (easy to use?). GLUT should try to find
  260.      the "largest".  So start with a large buffer size and
  261.      shrink until we find a matching one that exists. */
  262.  
  263.   for (i = 0; bufSizeList[i]; i++) {
  264.     /* XXX Assumes list[1] is where GLX_BUFFER_SIZE parameter
  265.        is. */
  266.     list[1] = bufSizeList[i];
  267.     vi = glXChooseVisual(__glutDisplay,
  268.       __glutScreen, list);
  269.     if (vi)
  270.       return vi;
  271.   }
  272.   return NULL;
  273. }
  274.  
  275. static XVisualInfo *
  276. getVisualInfoRGB(unsigned int mode)
  277. {
  278.   int list[32];
  279.   int n = 0;
  280.  
  281.   /* Should not be looking at display mode mask if
  282.      __glutDisplayString is non-NULL. */
  283.   assert(!__glutDisplayString);
  284.  
  285.   /* XXX Would a caching mechanism to minize the calls to
  286.      glXChooseVisual? You'd have to reference count
  287.      XVisualInfo* pointers.  Would also have to properly
  288.      interact with glutInitDisplayString. */
  289.  
  290.   list[n++] = GLX_RGBA;
  291.   list[n++] = GLX_RED_SIZE;
  292.   list[n++] = 1;
  293.   list[n++] = GLX_GREEN_SIZE;
  294.   list[n++] = 1;
  295.   list[n++] = GLX_BLUE_SIZE;
  296.   list[n++] = 1;
  297.   if (GLUT_WIND_HAS_ALPHA(mode)) {
  298.     list[n++] = GLX_ALPHA_SIZE;
  299.     list[n++] = 1;
  300.   }
  301.   if (GLUT_WIND_IS_DOUBLE(mode)) {
  302.     list[n++] = GLX_DOUBLEBUFFER;
  303.   }
  304.   if (GLUT_WIND_IS_STEREO(mode)) {
  305.     list[n++] = GLX_STEREO;
  306.   }
  307.   if (GLUT_WIND_HAS_DEPTH(mode)) {
  308.     list[n++] = GLX_DEPTH_SIZE;
  309.     list[n++] = 1;
  310.   }
  311.   if (GLUT_WIND_HAS_STENCIL(mode)) {
  312.     list[n++] = GLX_STENCIL_SIZE;
  313.     list[n++] = 1;
  314.   }
  315.   if (GLUT_WIND_HAS_ACCUM(mode)) {
  316.     list[n++] = GLX_ACCUM_RED_SIZE;
  317.     list[n++] = 1;
  318.     list[n++] = GLX_ACCUM_GREEN_SIZE;
  319.     list[n++] = 1;
  320.     list[n++] = GLX_ACCUM_BLUE_SIZE;
  321.     list[n++] = 1;
  322.     if (GLUT_WIND_HAS_ALPHA(mode)) {
  323.       list[n++] = GLX_ACCUM_ALPHA_SIZE;
  324.       list[n++] = 1;
  325.     }
  326.   }
  327. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample)
  328.   if (GLUT_WIND_IS_MULTISAMPLE(mode)) {
  329.     if (!__glutIsSupportedByGLX("GLX_SGIS_multisample"))
  330.       return NULL;
  331.     list[n++] = GLX_SAMPLES_SGIS;
  332.     /* XXX Is 4 a reasonable minimum acceptable number of
  333.        samples? */
  334.     list[n++] = 4;
  335.   }
  336. #endif
  337.   list[n] = (int) None; /* terminate list */
  338.  
  339.   return glXChooseVisual(__glutDisplay,
  340.     __glutScreen, list);
  341. }
  342.  
  343. XVisualInfo *
  344. __glutGetVisualInfo(unsigned int mode)
  345. {
  346.   /* XXX GLUT_LUMINANCE not implemented for GLUT 3.0. */
  347.   if (GLUT_WIND_IS_LUMINANCE(mode))
  348.     return NULL;
  349.  
  350.   if (GLUT_WIND_IS_RGB(mode))
  351.     return getVisualInfoRGB(mode);
  352.   else
  353.     return getVisualInfoCI(mode);
  354. }
  355.  
  356. XVisualInfo *
  357. __glutDetermineVisual(
  358.   unsigned int displayMode,
  359.   Bool * treatAsSingle,
  360.   XVisualInfo * (getVisualInfo) (unsigned int))
  361. {
  362.   XVisualInfo *vis;
  363.  
  364.   /* Should not be looking at display mode mask if
  365.      __glutDisplayString is non-NULL. */
  366.   assert(!__glutDisplayString);
  367.  
  368.   *treatAsSingle = GLUT_WIND_IS_SINGLE(displayMode);
  369.   vis = getVisualInfo(displayMode);
  370.   if (!vis) {
  371.     /* Fallback cases when can't get exactly what was asked
  372.        for... */
  373.     if (GLUT_WIND_IS_SINGLE(displayMode)) {
  374.       /* If we can't find a single buffered visual, try looking
  375.          for a double buffered visual.  We can treat a double
  376.          buffered visual as a single buffer visual by changing
  377.          the draw buffer to GL_FRONT and treating any swap
  378.          buffers as no-ops. */
  379.       displayMode |= GLUT_DOUBLE;
  380.       vis = getVisualInfo(displayMode);
  381.       *treatAsSingle = True;
  382.     }
  383.     if (!vis && GLUT_WIND_IS_MULTISAMPLE(displayMode)) {
  384.       /* If we can't seem to get multisampling (ie, not Reality
  385.          Engine class graphics!), go without multisampling.  It
  386.          is up to the application to query how many multisamples
  387.          were allocated (0 equals no multisampling) if the
  388.          application is going to use multisampling for more than
  389.          just antialiasing. */
  390.       displayMode &= ~GLUT_MULTISAMPLE;
  391.       vis = getVisualInfo(displayMode);
  392.     }
  393.   }
  394.   return vis;
  395. }
  396.  
  397. void
  398. __glutDefaultDisplay(void)
  399. {
  400.   /* XXX Remove the warning after GLUT 3.0. */
  401.   __glutWarning("The following is a new check for GLUT 3.0; update your code.");
  402.   __glutFatalError(
  403.     "redisplay needed for window %d, but no display callback.",
  404.     __glutCurrentWindow->num + 1);
  405. }
  406.  
  407. void
  408. __glutDefaultReshape(int width, int height)
  409. {
  410.   GLUToverlay *overlay;
  411.  
  412.   /* Adjust the viewport of the window (and overlay if one
  413.      exists). */
  414.   MAKE_CURRENT_WINDOW(__glutCurrentWindow);
  415.   glViewport(0, 0, (GLsizei) width, (GLsizei) height);
  416.   overlay = __glutCurrentWindow->overlay;
  417.   if (overlay) {
  418.     MAKE_CURRENT_OVERLAY(overlay);
  419.     glViewport(0, 0, (GLsizei) width, (GLsizei) height);
  420.   }
  421.   /* Make sure we are current to the current layer (application
  422.      should be able to count on the current layer not changing
  423.      unless the application explicitly calls glutUseLayer). */
  424.   MAKE_CURRENT_LAYER(__glutCurrentWindow);
  425. }
  426.  
  427. XVisualInfo *
  428. __glutDetermineWindowVisual(Bool * treatAsSingle, Bool * visAlloced, void **fbc)
  429. {
  430.   if (__glutDisplayString) {
  431.  
  432.     /* __glutDisplayString should be NULL except if
  433.        glutInitDisplayString has been called to register a
  434.        different display string.  Calling glutInitDisplayString
  435.        means using a string instead of an integer mask determine
  436.        the visual to use. Using the function pointer variable
  437.        __glutDetermineVisualFromString below avoids linking in
  438.        the code for implementing glutInitDisplayString (ie,
  439.        glut_dstr.o) unless glutInitDisplayString gets called by
  440.        the application. */
  441.  
  442.     assert(__glutDetermineVisualFromString);
  443.     *visAlloced = False;
  444.     *fbc = NULL;
  445.     return __glutDetermineVisualFromString(__glutDisplayString, treatAsSingle,
  446.       requiredWindowCriteria, numRequiredWindowCriteria, requiredWindowCriteriaMask, fbc);
  447.   } else {
  448.     *visAlloced = True;
  449.     *fbc = NULL;
  450.     return __glutDetermineVisual(__glutDisplayMode,
  451.       treatAsSingle, __glutGetVisualInfo);
  452.   }
  453. }
  454.  
  455. /* ARGSUSED5 */  /* Only Win32 uses gameMode parameter. */
  456. GLUTwindow *
  457. __glutCreateWindow(GLUTwindow * parent,
  458.   int x, int y, int width, int height, int gameMode)
  459. {
  460.   GLUTwindow *window;
  461.   XSetWindowAttributes wa;
  462.   unsigned long attribMask;
  463.   int winnum;
  464.   int i;
  465. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  466.   GLXFBConfigSGIX fbc;
  467. #else
  468.   void *fbc;
  469. #endif
  470.  
  471. #if defined(_WIN32)
  472.   WNDCLASS wc;
  473.   int style;
  474.  
  475.   if (!GetClassInfo(GetModuleHandle(NULL), "GLUT", &wc)) {
  476.     __glutOpenWin32Connection(NULL);
  477.   }
  478. #else
  479.   if (!__glutDisplay) {
  480.     __glutOpenXConnection(NULL);
  481.   }
  482. #endif
  483.   if (__glutGameModeWindow) {
  484.     __glutFatalError("cannot create windows in game mode.");
  485.   }
  486.   winnum = getUnusedWindowSlot();
  487.   window = (GLUTwindow *) malloc(sizeof(GLUTwindow));
  488.   if (!window) {
  489.     __glutFatalError("out of memory.");
  490.   }
  491.   window->num = winnum;
  492.  
  493. #if !defined(_WIN32)
  494.   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
  495.     &window->visAlloced, (void**) &fbc);
  496.   if (!window->vis) {
  497.     __glutFatalError(
  498.       "visual with necessary capabilities not found.");
  499.   }
  500.   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
  501. #endif
  502.   window->eventMask = StructureNotifyMask | ExposureMask;
  503.  
  504.   attribMask = CWBackPixmap | CWBorderPixel | CWColormap | CWEventMask;
  505.   wa.background_pixmap = None;
  506.   wa.border_pixel = 0;
  507.   wa.colormap = window->cmap;
  508.   wa.event_mask = window->eventMask;
  509.   if (parent) {
  510.     if (parent->eventMask & GLUT_HACK_STOP_PROPAGATE_MASK)
  511.       wa.event_mask |= GLUT_HACK_STOP_PROPAGATE_MASK;
  512.     attribMask |= CWDontPropagate;
  513.     wa.do_not_propagate_mask = parent->eventMask & GLUT_DONT_PROPAGATE_FILTER_MASK;
  514.   } else {
  515.     wa.do_not_propagate_mask = 0;
  516.   }
  517.  
  518.   /* Stash width and height before Win32's __glutAdjustCoords
  519.      possibly overwrites the values. */
  520.   window->width = width;
  521.   window->height = height;
  522.   window->forceReshape = True;
  523.   window->ignoreKeyRepeat = False;
  524.  
  525. #if defined(_WIN32)
  526.   __glutAdjustCoords(parent ? parent->win : NULL,
  527.     &x, &y, &width, &height);
  528.   if (parent) {
  529.     style = WS_CHILD;
  530.   } else {
  531.     if (gameMode) {
  532.       /* Game mode window should be a WS_POPUP window to
  533.          ensure that the taskbar is hidden by it.  A standard
  534.          WS_OVERLAPPEDWINDOW does not hide the task bar. */
  535.       style = WS_POPUP | WS_MAXIMIZE;
  536.     } else {
  537.       /* A standard toplevel window with borders and such. */
  538.       style = WS_OVERLAPPEDWINDOW;
  539.     }
  540.   }
  541.   window->win = CreateWindow("GLUT", "GLUT",
  542.     WS_CLIPSIBLINGS | WS_CLIPCHILDREN | style,
  543.     x, y, width, height, parent ? parent->win : __glutRoot,
  544.     NULL, GetModuleHandle(NULL), 0);
  545.   window->hdc = GetDC(window->win);
  546.   /* Must set the XHDC for fake glXChooseVisual & fake
  547.      glXCreateContext & fake XAllocColorCells. */
  548.   XHDC = window->hdc;
  549.   window->vis = __glutDetermineWindowVisual(&window->treatAsSingle,
  550.     &window->visAlloced, &fbc);
  551.   if (!window->vis) {
  552.     __glutFatalError(
  553.       "pixel format with necessary capabilities not found.");
  554.   }
  555.   if (!SetPixelFormat(window->hdc,
  556.       ChoosePixelFormat(window->hdc, window->vis),
  557.       window->vis)) {
  558.     __glutFatalError("SetPixelFormat failed during window create.");
  559.   }
  560.   __glutSetupColormap(window->vis, &window->colormap, &window->cmap);
  561.   /* Make sure subwindows get a windowStatus callback. */
  562.   if (parent) {
  563.     PostMessage(parent->win, WM_ACTIVATE, 0, 0);
  564.   }
  565.   window->renderDc = window->hdc;
  566. #else
  567.   window->win = XCreateWindow(__glutDisplay,
  568.     parent == NULL ? __glutRoot : parent->win,
  569.     x, y, width, height, 0,
  570.     window->vis->depth, InputOutput, window->vis->visual,
  571.     attribMask, &wa);
  572. #endif
  573.   window->renderWin = window->win;
  574. #if defined(GLX_VERSION_1_1) && defined(GLX_SGIX_fbconfig)
  575.   if (fbc) {
  576.     window->ctx = glXCreateContextWithConfigSGIX(__glutDisplay, fbc,
  577.       GLX_RGBA_TYPE_SGIX, None, __glutTryDirect);
  578.   } else
  579. #endif
  580.   {
  581.     window->ctx = glXCreateContext(__glutDisplay, window->vis,
  582.       None, __glutTryDirect);
  583.   }
  584.   if (!window->ctx) {
  585.     __glutFatalError(
  586.       "failed to create OpenGL rendering context.");
  587.   }
  588.   window->renderCtx = window->ctx;
  589. #if !defined(_WIN32)
  590.   window->isDirect = glXIsDirect(__glutDisplay, window->ctx);
  591.   if (__glutForceDirect) {
  592.     if (!window->isDirect)
  593.       __glutFatalError("direct rendering not possible.");
  594.   }
  595. #endif
  596.  
  597.   window->parent = parent;
  598.   if (parent) {
  599.     window->siblings = parent->children;
  600.     parent->children = window;
  601.   } else {
  602.     window->siblings = NULL;
  603.   }
  604.   window->overlay = NULL;
  605.   window->children = NULL;
  606.   window->display = __glutDefaultDisplay;
  607.   window->reshape = __glutDefaultReshape;
  608.   window->mouse = NULL;
  609.   window->motion = NULL;
  610.   window->passive = NULL;
  611.   window->entry = NULL;
  612.   window->keyboard = NULL;
  613.   window->keyboardUp = NULL;
  614.   window->windowStatus = NULL;
  615.   window->visibility = NULL;
  616.   window->special = NULL;
  617.   window->specialUp = NULL;
  618.   window->buttonBox = NULL;
  619.   window->dials = NULL;
  620.   window->spaceMotion = NULL;
  621.   window->spaceRotate = NULL;
  622.   window->spaceButton = NULL;
  623.   window->tabletMotion = NULL;
  624.   window->tabletButton = NULL;
  625. #ifdef _WIN32
  626.   window->joystick = NULL;
  627.   window->joyPollInterval = 0;
  628. #endif
  629.   window->tabletPos[0] = -1;
  630.   window->tabletPos[1] = -1;
  631.   window->shownState = 0;
  632.   window->visState = -1;  /* not VisibilityUnobscured,
  633.                              VisibilityPartiallyObscured, or
  634.                              VisibilityFullyObscured */
  635.   window->entryState = -1;  /* not EnterNotify or LeaveNotify */
  636.  
  637.   window->desiredConfMask = 0;
  638.   window->buttonUses = 0;
  639.   window->cursor = GLUT_CURSOR_INHERIT;
  640.  
  641.   /* Setup window to be mapped when glutMainLoop starts. */
  642.   window->workMask = GLUT_MAP_WORK;
  643. #ifdef _WIN32
  644.   if (gameMode) {
  645.     /* When mapping a game mode window, just show
  646.        the window.  We have already created the game
  647.        mode window with a maximize flag at creation
  648.        time.  Doing a ShowWindow(window->win, SW_SHOWNORMAL)
  649.        would be wrong for a game mode window since it
  650.        would unmaximize the window. */
  651.     window->desiredMapState = GameModeState;
  652.   } else {
  653.     window->desiredMapState = NormalState;
  654.   }
  655. #else
  656.   window->desiredMapState = NormalState;
  657. #endif
  658.   window->prevWorkWin = __glutWindowWorkList;
  659.   __glutWindowWorkList = window;
  660.  
  661.   /* Initially, no menus attached. */
  662.   for (i = 0; i < GLUT_MAX_MENUS; i++) {
  663.     window->menu[i] = 0;
  664.   }
  665.  
  666.   /* Add this new window to the window list. */
  667.   __glutWindowList[winnum] = window;
  668.  
  669.   /* Make the new window the current window. */
  670.   __glutSetWindow(window);
  671.  
  672.   __glutDetermineMesaSwapHackSupport();
  673.  
  674.   if (window->treatAsSingle) {
  675.     /* We do this because either the window really is single
  676.        buffered (in which case this is redundant, but harmless,
  677.        because this is the initial single-buffered context
  678.        state); or we are treating a double buffered window as a
  679.        single-buffered window because the system does not appear
  680.        to export any suitable single- buffered visuals (in which
  681.        the following are necessary). */
  682.     glDrawBuffer(GL_FRONT);
  683.     glReadBuffer(GL_FRONT);
  684.   }
  685.   return window;
  686. }
  687.  
  688. /* CENTRY */
  689. int APIENTRY
  690. glutCreateWindow(const char *title)
  691. {
  692.   static int firstWindow = 1;
  693.   GLUTwindow *window;
  694. #if !defined(_WIN32)
  695.   XWMHints *wmHints;
  696. #endif
  697.   Window win;
  698.   XTextProperty textprop;
  699.  
  700.   if (__glutGameModeWindow) {
  701.     __glutFatalError("cannot create windows in game mode.");
  702.   }
  703.   window = __glutCreateWindow(NULL,
  704.     __glutSizeHints.x, __glutSizeHints.y,
  705.     __glutInitWidth, __glutInitHeight,
  706.     /* not game mode */ 0);
  707.   win = window->win;
  708.   /* Setup ICCCM properties. */
  709.   textprop.value = (unsigned char *) title;
  710.   textprop.encoding = XA_STRING;
  711.   textprop.format = 8;
  712.   textprop.nitems = strlen(title);
  713. #if defined(_WIN32)
  714.   SetWindowText(win, title);
  715.   if (__glutIconic) {
  716.     window->desiredMapState = IconicState;
  717.   }
  718. #else
  719.   wmHints = XAllocWMHints();
  720.   wmHints->initial_state =
  721.     __glutIconic ? IconicState : NormalState;
  722.   wmHints->flags = StateHint;
  723.   XSetWMProperties(__glutDisplay, win, &textprop, &textprop,
  724.   /* Only put WM_COMMAND property on first window. */
  725.     firstWindow ? __glutArgv : NULL,
  726.     firstWindow ? __glutArgc : 0,
  727.     &__glutSizeHints, wmHints, NULL);
  728.   XFree(wmHints);
  729.   XSetWMProtocols(__glutDisplay, win, &__glutWMDeleteWindow, 1);
  730. #endif
  731.   firstWindow = 0;
  732.   return window->num + 1;
  733. }
  734.  
  735. int APIENTRY
  736. glutCreateSubWindow(int win, int x, int y, int width, int height)
  737. {
  738.   GLUTwindow *window;
  739.  
  740.   window = __glutCreateWindow(__glutWindowList[win - 1],
  741.     x, y, width, height, /* not game mode */ 0);
  742. #if !defined(_WIN32)
  743.   {
  744.     GLUTwindow *toplevel;
  745.  
  746.     toplevel = __glutToplevelOf(window);
  747.     if (toplevel->cmap != window->cmap) {
  748.       __glutPutOnWorkList(toplevel, GLUT_COLORMAP_WORK);
  749.     }
  750.   }
  751. #endif
  752.   return window->num + 1;
  753. }
  754. /* ENDCENTRY */
  755.  
  756. void
  757. __glutDestroyWindow(GLUTwindow * window,
  758.   GLUTwindow * initialWindow)
  759. {
  760.   GLUTwindow **prev, *cur, *parent, *siblings;
  761.  
  762.   /* Recursively destroy any children. */
  763.   cur = window->children;
  764.   while (cur) {
  765.     siblings = cur->siblings;
  766.     __glutDestroyWindow(cur, initialWindow);
  767.     cur = siblings;
  768.   }
  769.   /* Remove from parent's children list (only necessary for
  770.      non-initial windows and subwindows!). */
  771.   parent = window->parent;
  772.   if (parent && parent == initialWindow->parent) {
  773.     prev = &parent->children;
  774.     cur = parent->children;
  775.     while (cur) {
  776.       if (cur == window) {
  777.         *prev = cur->siblings;
  778.         break;
  779.       }
  780.       prev = &(cur->siblings);
  781.       cur = cur->siblings;
  782.     }
  783.   }
  784.   /* Unbind if bound to this window. */
  785.   if (window == __glutCurrentWindow) {
  786.     UNMAKE_CURRENT();
  787.     __glutCurrentWindow = NULL;
  788.   }
  789.   /* Begin tearing down window itself. */
  790.   if (window->overlay) {
  791.     __glutFreeOverlayFunc(window->overlay);
  792.   }
  793.   XDestroyWindow(__glutDisplay, window->win);
  794.   glXDestroyContext(__glutDisplay, window->ctx);
  795.   if (window->colormap) {
  796.     /* Only color index windows have colormap data structure. */
  797.     __glutFreeColormap(window->colormap);
  798.   }
  799.   /* NULLing the __glutWindowList helps detect is a window
  800.      instance has been destroyed, given a window number. */
  801.   __glutWindowList[window->num] = NULL;
  802.  
  803.   /* Cleanup data structures that might contain window. */
  804.   cleanWindowWorkList(window);
  805. #if !defined(_WIN32)
  806.   cleanStaleWindowList(window);
  807. #endif
  808.   /* Remove window from the "get window cache" if it is there. */
  809.   if (__glutWindowCache == window)
  810.     __glutWindowCache = NULL;
  811.  
  812.   if (window->visAlloced) {
  813.     /* Only free XVisualInfo* gotten from glXChooseVisual. */
  814.     XFree(window->vis);
  815.   }
  816.  
  817.   if (window == __glutGameModeWindow) {
  818.     /* Destroying the game mode window should implicitly
  819.        have GLUT leave game mode. */
  820.     __glutCloseDownGameMode();
  821.   }
  822.  
  823.   free(window);
  824. }
  825.  
  826. /* CENTRY */
  827. void APIENTRY
  828. glutDestroyWindow(int win)
  829. {
  830.   GLUTwindow *window = __glutWindowList[win - 1];
  831.  
  832.   if (__glutMappedMenu && __glutMenuWindow == window) {
  833.     __glutFatalUsage("destroying menu window not allowed while menus in use");
  834.   }
  835. #if !defined(_WIN32)
  836.   /* If not a toplevel window... */
  837.   if (window->parent) {
  838.     /* Destroying subwindows may change colormap requirements;
  839.        recalculate toplevel window's WM_COLORMAP_WINDOWS
  840.        property. */
  841.     __glutPutOnWorkList(__glutToplevelOf(window->parent),
  842.       GLUT_COLORMAP_WORK);
  843.   }
  844. #endif
  845.   __glutDestroyWindow(window, window);
  846. }
  847. /* ENDCENTRY */
  848.  
  849. void
  850. __glutChangeWindowEventMask(long eventMask, Bool add)
  851. {
  852.   if (add) {
  853.     /* Add eventMask to window's event mask. */
  854.     if ((__glutCurrentWindow->eventMask & eventMask) !=
  855.       eventMask) {
  856.       __glutCurrentWindow->eventMask |= eventMask;
  857.       __glutPutOnWorkList(__glutCurrentWindow,
  858.         GLUT_EVENT_MASK_WORK);
  859.     }
  860.   } else {
  861.     /* Remove eventMask from window's event mask. */
  862.     if (__glutCurrentWindow->eventMask & eventMask) {
  863.       __glutCurrentWindow->eventMask &= ~eventMask;
  864.       __glutPutOnWorkList(__glutCurrentWindow,
  865.         GLUT_EVENT_MASK_WORK);
  866.     }
  867.   }
  868. }
  869.  
  870. void APIENTRY
  871. glutDisplayFunc(GLUTdisplayCB displayFunc)
  872. {
  873.   /* XXX Remove the warning after GLUT 3.0. */
  874.   if (!displayFunc)
  875.     __glutFatalError("NULL display callback not allowed in GLUT 3.0; update your code.");
  876.   __glutCurrentWindow->display = displayFunc;
  877. }
  878.  
  879. void APIENTRY
  880. glutMouseFunc(GLUTmouseCB mouseFunc)
  881. {
  882.   if (__glutCurrentWindow->mouse) {
  883.     if (!mouseFunc) {
  884.       /* Previous mouseFunc being disabled. */
  885.       __glutCurrentWindow->buttonUses--;
  886.       __glutChangeWindowEventMask(
  887.         ButtonPressMask | ButtonReleaseMask,
  888.         __glutCurrentWindow->buttonUses > 0);
  889.     }
  890.   } else {
  891.     if (mouseFunc) {
  892.       /* Previously no mouseFunc, new one being installed. */
  893.       __glutCurrentWindow->buttonUses++;
  894.       __glutChangeWindowEventMask(
  895.         ButtonPressMask | ButtonReleaseMask, True);
  896.     }
  897.   }
  898.   __glutCurrentWindow->mouse = mouseFunc;
  899. }
  900.  
  901. void APIENTRY
  902. glutMotionFunc(GLUTmotionCB motionFunc)
  903. {
  904.   /* Hack.  Some window managers (4Dwm by default) will mask
  905.      motion events if the client is not selecting for button
  906.      press and release events. So we select for press and
  907.      release events too (being careful to use reference
  908.      counting).  */
  909.   if (__glutCurrentWindow->motion) {
  910.     if (!motionFunc) {
  911.       /* previous mouseFunc being disabled */
  912.       __glutCurrentWindow->buttonUses--;
  913.       __glutChangeWindowEventMask(
  914.         ButtonPressMask | ButtonReleaseMask,
  915.         __glutCurrentWindow->buttonUses > 0);
  916.     }
  917.   } else {
  918.     if (motionFunc) {
  919.       /* Previously no mouseFunc, new one being installed. */
  920.       __glutCurrentWindow->buttonUses++;
  921.       __glutChangeWindowEventMask(
  922.         ButtonPressMask | ButtonReleaseMask, True);
  923.     }
  924.   }
  925.   /* Real work of selecting for passive mouse motion.  */
  926.   __glutChangeWindowEventMask(
  927.     Button1MotionMask | Button2MotionMask | Button3MotionMask,
  928.     motionFunc != NULL);
  929.   __glutCurrentWindow->motion = motionFunc;
  930. }
  931.  
  932. void APIENTRY
  933. glutPassiveMotionFunc(GLUTpassiveCB passiveMotionFunc)
  934. {
  935.   __glutChangeWindowEventMask(PointerMotionMask,
  936.     passiveMotionFunc != NULL);
  937.  
  938.   /* Passive motion also requires watching enters and leaves so
  939.      that a fake passive motion event can be generated on an
  940.      enter. */
  941.   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
  942.     __glutCurrentWindow->entry != NULL || passiveMotionFunc != NULL);
  943.  
  944.   __glutCurrentWindow->passive = passiveMotionFunc;
  945. }
  946.  
  947. void APIENTRY
  948. glutEntryFunc(GLUTentryCB entryFunc)
  949. {
  950.   __glutChangeWindowEventMask(EnterWindowMask | LeaveWindowMask,
  951.     entryFunc != NULL || __glutCurrentWindow->passive);
  952.   __glutCurrentWindow->entry = entryFunc;
  953.   if (!entryFunc) {
  954.     __glutCurrentWindow->entryState = -1;
  955.   }
  956. }
  957.  
  958. void APIENTRY
  959. glutWindowStatusFunc(GLUTwindowStatusCB windowStatusFunc)
  960. {
  961.   __glutChangeWindowEventMask(VisibilityChangeMask,
  962.     windowStatusFunc != NULL);
  963.   __glutCurrentWindow->windowStatus = windowStatusFunc;
  964.   if (!windowStatusFunc) {
  965.     /* Make state invalid. */
  966.     __glutCurrentWindow->visState = -1;
  967.   }
  968. }
  969.  
  970. static void
  971. visibilityHelper(int status)
  972. {
  973.   if (status == GLUT_HIDDEN || status == GLUT_FULLY_COVERED)
  974.     __glutCurrentWindow->visibility(GLUT_NOT_VISIBLE);
  975.   else
  976.     __glutCurrentWindow->visibility(GLUT_VISIBLE);
  977. }
  978.  
  979. void APIENTRY
  980. glutVisibilityFunc(GLUTvisibilityCB visibilityFunc)
  981. {
  982.   __glutCurrentWindow->visibility = visibilityFunc;
  983.   if (visibilityFunc)
  984.     glutWindowStatusFunc(visibilityHelper);
  985.   else
  986.     glutWindowStatusFunc(NULL);
  987. }
  988.  
  989. void APIENTRY
  990. glutReshapeFunc(GLUTreshapeCB reshapeFunc)
  991. {
  992.   if (reshapeFunc) {
  993.     __glutCurrentWindow->reshape = reshapeFunc;
  994.   } else {
  995.     __glutCurrentWindow->reshape = __glutDefaultReshape;
  996.   }
  997. }
  998.